#include <stdio.h>
#include "modbus.h"
#include <cJSON.h>
#include <msg_queue.h>
#include <shmem.h>
#include <msg_queue_peer.h>
#include <string.h>
#include <pthread.h>
#include <file_opt.h>
#include <stdlib.h>
#include <unistd.h>

struct msgbuf
{
    long mtype;
    char mdata[256];
};

union val_t
{ 
    int b_val;  //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val;  //浮点值存储空间
};

struct std_node
{
	int key;  //唯一键值
	int type;  //数据点类型
    int dev_type;  //属于哪个设备：m0或modbus或者手机APP
	union val_t old_val;  //变化上报后需要更新旧值
    union val_t new_val;  //从共享内存取出最新数据，放到new_val中
    int ret;  //默认为-1，采集成功后设置为0，采集失败再置-1
};
//声明线程1的方法
void *handle1(void *arg);

int main(int argc, const char *argv[])
{
	
    //读 wenbeng.json 文本***********************************************************************
	  char buf[1024] = {0};    
	  int ret = fileopt_readall("./wenbeng.json", buf);
      if(ret < 0)
      {
       printf("read err.\n");
       return -1;
      }
	//从缓冲区中解析出JSON结构  得到手机端的IP地址和端口号                                 
       cJSON *root = cJSON_Parse(buf);//得到总节点
	   //cJSON *item = cJSON_GetObjectItem(root, "report");//得到 report 的节点
	  // cJSON *item01 = cJSON_GetObjectItem(item, "type");//得到 report-type 的节点
	  // cJSON *item02 = cJSON_GetObjectItem(item, "period");//得到 report-period 的节点
       cJSON *item1 = cJSON_GetObjectItem(root, "mb_app");//得到 mp_app 的节点
	   cJSON *item2 = cJSON_GetObjectItem(item1, "addr");//得到 手机IP 的节点 
	   cJSON *item3 = cJSON_GetObjectItem(item1, "port");//得到 手机端口号 的节点  
	//modbus 实例初始化*****************************************************************
	modbus_t *ctx = modbus_new_tcp(item2->valuestring, item3->valueint);
	if(ctx == NULL)
	{
		perror("modbus new tcp err");
		return -1;
	}
	//设置从机id
	modbus_set_slave(ctx,1);
	//建立链接
	if(modbus_connect(ctx) < 0)
	{
		perror("connect err");
		modbus_free(ctx);
		return -1;
	}
	printf("connect success\n");

    //创建多线程**********************************************************************
	pthread_t t1;
	// 创建线程1(用来不停的往共享内存放光照强度,X,Y,Z轴数据)
		if(pthread_create(&t1, NULL, handle1, (void *)ctx) == -1){
			puts("fail to create pthread 1");
			exit(1);
		}

	//创建消息队列(用来接收上报进程的指令并向上报进程回馈控制是否成功)**********************************************************************
	struct msgbuf recv_buf;
	struct msgbuf send_buf;
	send_buf.mtype = 2L;
    //向上报进程回馈控制是否成功要用json格式
	cJSON *answer_root = cJSON_CreateObject();
	cJSON_AddItemToObject(answer_root, "type", cJSON_CreateNumber(2));
    cJSON_AddItemToObject(answer_root, "result", cJSON_CreateNumber(0));
    cJSON_AddItemToObject(answer_root, "msg", cJSON_CreateString("控制成功"));

	while(1)
	{
		if(msg_queue_recv("msgn", &recv_buf, sizeof(recv_buf), 1L, 0) < 0)//得到数据上报进程发来的json字符串,保存在recv_buf结构提中
		{
			perror("recvb error:");
		}
		//从缓冲区中解析出JSON结构                                   
		root = cJSON_Parse(recv_buf.mdata);//得到总节点
		bzero(recv_buf.mdata,sizeof(recv_buf.mdata));
		cJSON *item = cJSON_GetObjectItem(root, "type");
		item1 = cJSON_GetObjectItem(root, "data"); 
		item2 = cJSON_GetObjectItem(item1, "key");
		item3 = cJSON_GetObjectItem(item1, "val"); 
		if(item->valueint == 1)//1为采集信息
		{
			if(item2->valueint == 1)//1代表灯泡
			{

			}else if(item2->valueint == 2){//2代表蜂鸣器

			}

		}
		else if(item->valueint == 2)//2为控制指令
		{
		//控制灯泡亮灭************************************
			if((item2->valueint == 1) && (atoi(item3->valuestring) == 1))//控制灯泡亮灭
			{ printf("nihh\n");
				modbus_write_bit(ctx, 0, 1);//灯泡开
				sprintf(send_buf.mdata, "%s", cJSON_Print(answer_root));
				if(msg_queue_send("msgn", &send_buf, sizeof(send_buf), 2L) < 0)
				{
					perror("send 2L err.");
				}
			}
			else if((item2->valueint == 1) && (atoi(item3->valuestring) == 0))
			{
				modbus_write_bit(ctx, 0, 0);//灯泡关
				sprintf(send_buf.mdata, "%s", cJSON_Print(answer_root));
				if(msg_queue_send("msgn", &send_buf, sizeof(send_buf), 2L) < 0)
				{
					perror("send 2L err.");
				}
			}
        //控制蜂鸣器开关************************************
			if((item2->valueint == 2) && (atoi(item3->valuestring) == 1))//控制蜂鸣器开关
			{ printf("nihh\n");
				modbus_write_bit(ctx, 1, 1);//蜂鸣器开
				sprintf(send_buf.mdata, "%s", cJSON_Print(answer_root));
				if(msg_queue_send("msgn", &send_buf, sizeof(send_buf), 2L) < 0)
				{
					perror("send 2L err.");
				}
			}
			else if((item2->valueint == 1) && (atoi(item3->valuestring) == 0))
			{
				modbus_write_bit(ctx, 1, 0);//蜂鸣器关
				sprintf(send_buf.mdata, "%s", cJSON_Print(answer_root));
				if(msg_queue_send("msgn", &send_buf, sizeof(send_buf), 2L) < 0)
				{
					perror("send 2L err.");
				}
			}  
		}
	}
	//回收线程资源
	if(pthread_join(t1, NULL) == -1)
	{
		puts("fail to recollect t1");
		exit(1);
	}
	//释放ctx;
	modbus_free(ctx);
	//关闭套接字
	modbus_close(ctx);
	return 0;
}

/* 线程1的方法*****************************************************************************************************************************
*****************************************************************************************************************************************/
void *handle1(void *arg)
{ 
	modbus_t *ctx = (modbus_t *)arg;
	
	uint16_t temp[256]={0};
	float buf[24] = {0};

//创建共享内存*********************************************************************
 struct shm_param para;
	//共享内存初始化
	int ret = shm_init(&para, "shm_test", 1024);
	if(ret < 0)
	{
		perror("共享内存初始化失败.");
		return -1;
	}
	//得到共享内存空间地址
	struct std_node *addr = shm_getaddr(&para);
	if(addr == NULL)
	{
		return NULL;
	}
    char *q = NULL;
	float x = 0,y = 0,z = 0;
	int light_intensity = 0;
	//循环不断的每间隔一秒读取APP数据,然后放入共享内存****************************************
	while(1)
	{
		if(modbus_read_registers(ctx,0,4,temp) == -1)
		{
			perror("read err3");
			return NULL;
		}
		//转化APP数据********
		q = (char*)temp;
		buf[0] = q[0]+(int)q[1]*100;//光照
		buf[1] = q[3]+((float)q[2])/100;//X轴
		buf[2] = q[5]+((float)q[4])/100;//Y轴
		buf[3] = q[7]+((float)q[6])/100;//Z轴
		//赋值*********
		addr[0].key = 201; //光照数据
		addr[0].type = 2;
		addr[0].dev_type = 1;
		addr[0].old_val.i_val = light_intensity;
		addr[0].new_val.i_val = buf[0];


		addr[1].key = 202; //X轴
		addr[1].type = 3;
		addr[1].dev_type = 2;
		addr[1].old_val.f_val = x;
		addr[1].new_val.f_val = buf[1];

		addr[2].key = 203;  //Y轴
		addr[2].type = 3;
		addr[2].dev_type = 3;
		addr[2].old_val.f_val = y;
		addr[2].new_val.f_val = buf[2];

		addr[3].key = 204;  //Z轴
		addr[3].type = 3;
		addr[3].dev_type = 4;
		addr[3].old_val.f_val = z;
		addr[3].new_val.f_val = buf[3];

		sleep(1);

		light_intensity = buf[0];
		x = buf[1];
		y = buf[2];
		z = buf[3];
		/*if(buf[0] > 150){
		  modbus_write_bit(ctx, 0, 0);//灯泡关
		  }else{
		  modbus_write_bit(ctx, 0, 1);//灯泡开
		  }
		  printf("光照强度:%d\n", (int)buf[0]);
		  for(int i = 1; i < 4; i++){
		  printf("%.2f  ",buf[i]);
		  }
		  putchar(10);
		  */

	}
	   shm_del(&para);
	   return NULL;

}
//线程2的方法
/*void *handle2(void *arg)
{ 
	//创建共享内存*********************************************************************
static struct shm_param para;
	//共享内存初始化
	int ret = shm_init(&para, "shm_test", 1024);
	if(ret < 0)
	{
		perror("共享内存初始化失败.");
		return -1;
	}
	//得到共享内存空间地址
	struct student *addr = shm_getaddr(&para);
	if(addr == NULL)
	{
		return -1;
	}

	shm_del(&para);
	return NULL;
}*/
